package 反射.代理;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/*
一、作用
//CallbackFilter作用：在CGLib回调时可以设置对不同方法执行不同的回调逻辑，或者根本不执行回调。
在JDK动态代理中并没有类似的功能，对InvocationHandler接口方法的调用对代理类内的所以方法都有效。
二、示例：

CGLib 的 CallbackFilter 接口将 Enhancer 生成的子类的方法映射到特定的回调。为每个方法选择的回调类型会影响子类中为该方法生成的字节码，并且
在类的生命周期内无法更改。

注意：CallbackFilter 实现应该是轻量级的，因为 CGLib 可能会使 CallbackFilter 对象保持活动状态以启用生成类的缓存。首选使用静态类来实
现 CallbackFilter。

在 CallbackFilter 中，定义了 accept() 和 equals() 方法，定义分别如下：
 •accept 方法: int accept(java.lang.reflect.Method method)
   该方法将方法映射到回调（Callback）。其中，method 参数表示被拦截的方法。该方法将返回一个回调数组的索
   引（由 Enhancer.setCallbacks(net.sf.cglib.proxy.Callback[]) 指定）。

 •equals 方法: boolean equals(java.lang.Object o)
   使用中的 CallbackFilter 会影响 Enhancer 将使用哪个缓存类，因此这提醒您应该正确实现自定义 CallbackFilter 实现的 equals 和 hashCode，以提高性能。

下面通过一个完整实例，介绍怎样使用 CallbackFilter。

（1）定义被代理类，代码如下：
*/
class HelloWorld {//被代理的类

    public String test(String msg) {//有返回
        return msg;
    }
    public void hello() {//无返回
        System.out.println("hello world");
    }
}
//（2）定义客户端，代码如下：

//import net.sf.cglib.proxy.*;
//import java.lang.reflect.Method;
 
public class CGLIB之CallbackFilter {//验证 CallbackFilter 接口的简单用法
 
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelloWorld.class);
        // 实现自定义的 CallbackFilter，根据方法名称指定不同的 Callback 回调
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                return method.getName().equals("test") ? 0 : 1; //据方法名返回int n,n代表下文Callback[]数组下标，
                //如：方法名"test"返回0，则执行Callback[]数组下标0即new FixedValue()
            }
        });
        // 指定多个 Callback 回调
        enhancer.setCallbacks(new Callback[]{
            new FixedValue() {
                @Override
                public Object loadObject() throws Exception {
                    return "Fixed Value";
                }
            },
            new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
                    System.out.println("call intercept before");
                    Object result = proxy.invokeSuper(obj, args);
                    System.out.println("call intercept after");
                    return result;
                }
            }
        });
 
        HelloWorld proxy = (HelloWorld)enhancer.create();
        System.out.println("test=" + proxy.test("hello world"));
        proxy.hello();
    }
 
}
/*
运行上面程序，输出如下：

test=Fixed Value
call intercept before
hello world
call intercept after
上面代码中，有如下代码：

enhancer.setCallbackFilter(new CallbackFilter() {
    @Override
    public int accept(Method method) {
        return method.getName().equals("test") ? 0 : 1;
    }
});
该代码将判断当前拦截的方法名称是否为“test”，如果是，则返回0；否则，返回1。需要注意，这里的 0 和 1 其实表示一个下标值。CGLib 将根据该下标值
到 enhancer.setCallbacks(new Callback[]{}); 代码设置的回调数组中获取 Callback 实例。例如：

enhancer.setCallbacks(new Callback[]{
    new FixedValue() {
        @Override
        public Object loadObject() throws Exception {
            return "Fixed Value";
        }
    },
    new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args,
                                MethodProxy proxy) throws Throwable {
            System.out.println("call intercept before");
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("call intercept after");
            return result;
        }
    }
});
上面代码设置了两个 Callback 回调，分别为 FixedValue 和 MethodInterceptor。前者的下标为0，后者为 1；所以，我们在 CallbackFilter 的 accept() 
方法中，根据方法名称是否等于“test”来返回 0 和 1。实质上就是指定方法名为 test 的方法使用 FixedValue 类型回调；其他方法均使用 MethodInterceptor 类
型回调*/